package cc.rengu.igas.share.core.realize.impl;

import cc.rengu.igas.bomp.facade.base.Header;
import cc.rengu.igas.bomp.facade.bean.TxnLimitCfgBean;
import cc.rengu.igas.bomp.facade.request.ChannelLimitCfgQueryRequest;
import cc.rengu.igas.bomp.facade.response.ChannelLimitCfgQueryResponse;
import cc.rengu.igas.bomp.facade.result.Result;
import cc.rengu.igas.share.common.constant.ShareParamConstant;
import cc.rengu.igas.share.common.constant.ShareServiceConstant;
import cc.rengu.igas.share.core.realize.PublicService;
import cc.rengu.jradp.mods.trmsg.TransCheck;
import cc.rengu.oltp.service.common.constant.AppConfigConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.entity.SysParam;
import cc.rengu.oltp.service.common.enums.AcctTypeEnum;
import cc.rengu.oltp.service.common.enums.ChannelEnum;
import cc.rengu.oltp.service.common.enums.OltpRpcdEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.TransLimitInfo;
import cc.rengu.oltp.service.realize.DubboService;
import cc.rengu.oltp.service.realize.SysParamService;
import cc.rengu.oltp.service.realize.TransLimitService;
import cc.rengu.oltp.service.realize.impl.DubboServiceImpl;
import cc.rengu.oltp.service.realize.impl.SysParamServiceImpl;
import cc.rengu.oltp.service.realize.impl.TransLimitServiceImpl;
import cc.rengu.oltp.utility.util.*;
import cc.rengu.utility.log.RgLog;
import cc.rengu.utility.log.RgLogger;

import java.util.ArrayList;
import java.util.List;

public class PublicServiceImpl implements PublicService {

    private final RgLogger rglog = RgLog.getLogger(this.getClass().getName());

    @Override
    public void checkInputValidity(String srcId, String txnNum) throws Exception {
        StringBuilder result = null;
        String[] checkResult = TransCheck.checkTransStruct(srcId, txnNum, "IN");
        if (checkResult == null) {
            rglog.debug("未配置检查规则");
            return;
        }
        for (String s : checkResult) {
            rglog.debug("报文中字段[{}]必须出现", s);
            if (result == null) {
                result = new StringBuilder("以下必填字段没有上送:");
            }
            result.append(s).append(",");
        }
        if (result != null) {
            rglog.error("{}", result.toString());
            throw new BizException(OltpRpcdEnum.PARAM_IS_EMPTY_OR_NULL.getRespCode(), OltpRpcdEnum.PARAM_IS_EMPTY_OR_NULL.getRespDesc());
        }
    }

    @Override
    public void checkInputParamLegal() throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String instId = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.INST_ID);
        //获取需要校验参数合法性的字段 以,号分隔，若不存在则不校验
        SysParamService sysParamService = new SysParamServiceImpl();
        SysParam legalParam = sysParamService.getSysParamInfo(instId, ShareParamConstant.SHARE_SYS_PARAM, ShareParamConstant.PARAM_LEGAL_FILED);
        if (null == legalParam || !ShareParamConstant.SHARE_SYS_PARAM.equals(legalParam.getParamStatus())) {
            rglog.info("未配置需要校验合法性的参数信息,或配置的参数信息未生效。不做参数合法性校验");
            return;
        }
        //对配置的需要校验参数合法性的数据进行校验
        String[] legalParamFieds = legalParam.getParamValue().split(",");
        for (String legalParamFied : legalParamFieds) {
            /* 获取验证参数合法性的字段类型 */
            String[] fieldBuf = legalParamFied.split(":");
            //参数内部节点
            String fieldKey = fieldBuf[0];
            //校验参数的类型 用以区分当前参数匹配何种校验规则
            String fieldType = fieldBuf[1];
            //参数类型内部节点值 例:证件类型字段的内部节点
            String fieldTypeKey = "";
            if (fieldBuf.length == 3) {
                fieldTypeKey = fieldBuf[2];
            }
            if (fieldKey.contains("$n")) {
                int index = 1;
                String nextfield = fieldKey.replace("$n", String.valueOf(index));
                String nextfieldType = fieldTypeKey.replace("$n", String.valueOf(index));
                do {
                    String fieldValue = xmlTreeUtil.getXmlTreeStringValue(nextfield);
                    if (StringUtil.isEmptyOrNull(fieldValue)) {
                        rglog.trace("待验证参数合法性的字段未上传:<{}>", fieldKey);
                        continue;
                    }
                    String fieldKeyValue = StringUtil.isEmptyOrNull(nextfieldType) ? "" : xmlTreeUtil.getXmlTreeStringValue(nextfieldType);
                    checkInputParamLegalByFieldType(fieldValue, fieldType, fieldKeyValue);
                    index++;
                    nextfield = fieldKey.replace("$n", String.valueOf(index));
                    nextfieldType = fieldTypeKey.replace("$n", String.valueOf(index));
                } while (!StringUtil.isEmptyOrNull(xmlTreeUtil.getXmlTreeStringValue(nextfield)));
            } else {
                String fieldValue = xmlTreeUtil.getXmlTreeStringValue(fieldKey);
                if (StringUtil.isEmptyOrNull(fieldValue)) {
                    rglog.trace("待验证参数合法性的字段未上传:<{}>", fieldKey);
                    continue;
                }
                String fieldKeyValue = StringUtil.isEmptyOrNull(fieldTypeKey) ? "" : xmlTreeUtil.getXmlTreeStringValue(fieldTypeKey);
                checkInputParamLegalByFieldType(fieldValue, fieldType, fieldKeyValue);
            }
        }
    }

    @Override
    public boolean channelLimitCheck(String instId, String txnNum, String transAmt, String channelId, String channelTxn, String limitAcctType) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        /* 获取通道限额配置信息 */
        Header header = new Header();
        header.setInstId(instId);
        header.setSrcSysId(ChannelEnum.BOMP.getChannelType());
        header.setChanlId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SRC_SYS_ID));
        header.setTxnNum("M00BM055");
        header.setBizType("00");
        header.setVersion(ShareParamConstant.DUBBO_VSERSION);
        header.setTraceNo(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM));
        header.setTransTime(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_TIME));
        header.setTransDate(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_DATE));
        ChannelLimitCfgQueryRequest channelLimitCfgQueryRequest = new ChannelLimitCfgQueryRequest();
        channelLimitCfgQueryRequest.setHeader(header);
        channelLimitCfgQueryRequest.setChannelId(channelId);
        channelLimitCfgQueryRequest.setChannelTxn(channelTxn);
        channelLimitCfgQueryRequest.setLimitAcctType(limitAcctType);
        DubboService dubboService = new DubboServiceImpl();
        Result<ChannelLimitCfgQueryResponse> callResult;
        String callMode = XmlConfigUtil.getXmlConfigCacheKeyValue(AppConfigConstant.APPLICATION_CONF_NODE, AppConfigConstant.USER_SERVICE_CALL_MODE);
        if (!StringUtil.isEmptyOrNull(callMode)) {
            if (!"0".equals(callMode.trim()) && !"1".equals(callMode.trim())) {
                rglog.error("用户相关信息获取调用模式<{}>参数配置错误:0-本地调用，1-微服务调用!", callMode.trim());
                throw new BizException("内管相关信息获取方式配置有误:<{}>", callMode);
            }
        } else {
            /* 默认为跨应用调用 */
            callMode = "1";
        }
        if ("0".equals(callMode)) {
            Class clasz = Class.forName(ShareServiceConstant.BOMP_PUBLIC_QUERY_SERVICE_INNER_PATH);
            callResult = (Result<ChannelLimitCfgQueryResponse>) dubboService.callDubboInnerMethod(clasz, ShareServiceConstant.BOMP_CHANNEL_LIMIT_CFG_QUERY_METHOD, channelLimitCfgQueryRequest);
        } else {
            callResult = (Result<ChannelLimitCfgQueryResponse>) dubboService.callDubboService(ShareServiceConstant.BOMP_PUBLIC_QUERY_SERVICE, ShareServiceConstant.BOMP_CHANNEL_LIMIT_CFG_QUERY_METHOD, channelLimitCfgQueryRequest);
        }
        //调用失败callResult.getResult()为空
        if (null == callResult || null == callResult.getResult()) {
            rglog.info("通道未配置限额配置信息，默认按支付密码认证,instId:<{}>,channelId:<{}>,channelTxn:<{}>", instId, channelId, channelTxn);
            return true;
        }
        /* 通道限额检查 */
        List<TxnLimitCfgBean> txnLimitCfgBeanList = new ArrayList<>();
        if(null != callResult.getResult().getChannelLimitList()){
            txnLimitCfgBeanList.addAll(callResult.getResult().getChannelLimitList());
        }
        if(null != callResult.getResult().getChannelTxnLimitList()) {
            txnLimitCfgBeanList.addAll(callResult.getResult().getChannelTxnLimitList());
        }
        if (txnLimitCfgBeanList.isEmpty()) {
            rglog.debug("不存在限额配置，不检查");
            return true;
        }
        List<TransLimitInfo> transLimitInfoList = new ArrayList<>();
        for (TxnLimitCfgBean txnLimitCfgBean : txnLimitCfgBeanList) {
            TransLimitInfo transLimitInfo = new TransLimitInfo();
            BeanUtil.beanCopy(txnLimitCfgBean, transLimitInfo);
            if (StringUtil.isEmptyOrNull(transLimitInfo.getLimitAcctType())) {
                transLimitInfo.setLimitAcctType(AcctTypeEnum.ALL.getAcctType());
            }
            transLimitInfoList.add(transLimitInfo);
        }
        TransLimitService transLimitService = new TransLimitServiceImpl(instId, txnNum, null);
        if (!transLimitService.transLimitCheck(transAmt, transLimitInfoList)) {
            rglog.error("限额检查不通过");
            return false;
        }
        return true;
    }

    @Override
    public boolean channelLimitStatis(String instId, String txnNum, String transAmt, String channelId, String channelTxn, String limitAcctType) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        /* 获取通道限额配置信息 */
        Header header = new Header();
        header.setInstId(instId);
        header.setSrcSysId(ChannelEnum.BOMP.getChannelType());
        header.setChanlId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SRC_SYS_ID));
        header.setTxnNum("M00BM055");
        header.setBizType("00");
        header.setVersion(ShareParamConstant.DUBBO_VSERSION);
        header.setTraceNo(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM));
        header.setTransTime(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_TIME));
        header.setTransDate(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_DATE));
        ChannelLimitCfgQueryRequest channelLimitCfgQueryRequest = new ChannelLimitCfgQueryRequest();
        channelLimitCfgQueryRequest.setHeader(header);
        channelLimitCfgQueryRequest.setChannelId(channelId);
        channelLimitCfgQueryRequest.setChannelTxn(channelTxn);
        channelLimitCfgQueryRequest.setLimitAcctType(limitAcctType);
        DubboService dubboService = new DubboServiceImpl();
        Result<ChannelLimitCfgQueryResponse> callResult;
        String callMode = XmlConfigUtil.getXmlConfigCacheKeyValue(AppConfigConstant.APPLICATION_CONF_NODE, AppConfigConstant.USER_SERVICE_CALL_MODE);
        if (!StringUtil.isEmptyOrNull(callMode)) {
            if (!"0".equals(callMode.trim()) && !"1".equals(callMode.trim())) {
                rglog.error("用户相关信息获取调用模式<{}>参数配置错误:0-本地调用，1-微服务调用!", callMode.trim());
                throw new BizException("内管相关信息获取方式配置有误:<{}>", callMode);
            }
        } else {
            /* 默认为跨应用调用 */
            callMode = "1";
        }
        if ("0".equals(callMode)) {
            Class clasz = Class.forName(ShareServiceConstant.BOMP_PUBLIC_QUERY_SERVICE_INNER_PATH);
            callResult = (Result<ChannelLimitCfgQueryResponse>) dubboService.callDubboInnerMethod(clasz, ShareServiceConstant.BOMP_CHANNEL_LIMIT_CFG_QUERY_METHOD, channelLimitCfgQueryRequest);
        } else {
            callResult = (Result<ChannelLimitCfgQueryResponse>) dubboService.callDubboService(ShareServiceConstant.BOMP_PUBLIC_QUERY_SERVICE, ShareServiceConstant.BOMP_CHANNEL_LIMIT_CFG_QUERY_METHOD, channelLimitCfgQueryRequest);
        }
        if (null == callResult || null == callResult.getResult()) {
            rglog.info("通道未配置限额配置信息，默认按支付密码认证,instId:<{}>,channelId:<{}>,channelTxn:<{}>", instId, channelId, channelTxn);
            return true;
        }
        /* 通道限额检查 */
        List<TxnLimitCfgBean> txnLimitCfgBeanList = new ArrayList<>();
        txnLimitCfgBeanList.addAll(callResult.getResult().getChannelLimitList());
        txnLimitCfgBeanList.addAll(callResult.getResult().getChannelTxnLimitList());
        if (txnLimitCfgBeanList.isEmpty()) {
            rglog.debug("不存在限额配置，不检查");
            return true;
        }
        List<TransLimitInfo> transLimitInfoList = new ArrayList<>();
        for (TxnLimitCfgBean txnLimitCfgBean : txnLimitCfgBeanList) {
            TransLimitInfo transLimitInfo = new TransLimitInfo();
            BeanUtil.beanCopy(txnLimitCfgBean, transLimitInfo);
            if (StringUtil.isEmptyOrNull(transLimitInfo.getLimitAcctType())) {
                transLimitInfo.setLimitAcctType(AcctTypeEnum.ALL.getAcctType());
            }
            transLimitInfoList.add(transLimitInfo);
        }
        TransLimitService transLimitService = new TransLimitServiceImpl(instId, txnNum, null);
        if (!transLimitService.transLimitStatis(transAmt, transLimitInfoList)) {
            rglog.error("限额统计失败");
            return false;
        }
        return true;
    }

    /**
     * 参数合法性校验的具体实现方法
     *
     * @param paramValue     内部树节点的key值
     * @param fieldType      校验参数的类型：1-手机号，2-银行卡，3-证件号，4-交易金额
     * @param paramTypeValue 参数类型内部节点值
     */
    void checkInputParamLegalByFieldType(String paramValue, String fieldType, String paramTypeValue) {
        switch (fieldType) {
            case "1":
                if (!RegexUtil.checkPhoneNo(paramValue)) {
                    rglog.info("传入手机号合法性校验失败:<{}>", paramValue);
                    throw new BizException(OltpRpcdEnum.PARAM_IS_NOT_VALIDITY.getRespCode(), OltpRpcdEnum.PARAM_IS_NOT_VALIDITY.getRespDesc());
                }
                break;
            case "2":
                if (!RegexUtil.checkCardNo(paramValue)) {
                    rglog.info("传入银行卡号合法性校验失败:<{}>", paramValue);
                    throw new BizException(OltpRpcdEnum.PARAM_IS_NOT_VALIDITY.getRespCode(), OltpRpcdEnum.PARAM_IS_NOT_VALIDITY.getRespDesc());
                }
                break;
            case "3":
                if ("01".equals(paramTypeValue) && !RegexUtil.checkCertNo(paramValue)) {
                    rglog.info("传入身份证号合法性校验失败:<{}>", paramValue);
                    throw new BizException(OltpRpcdEnum.PARAM_IS_NOT_VALIDITY.getRespCode(), OltpRpcdEnum.PARAM_IS_NOT_VALIDITY.getRespDesc());
                }
                break;
            case "4":
                if (!RegexUtil.checkAmt(paramValue)) {
                    rglog.info("传入交易金额合法性校验失败:<{}>", paramValue);
                    throw new BizException(OltpRpcdEnum.PARAM_IS_NOT_VALIDITY.getRespCode(), OltpRpcdEnum.PARAM_IS_NOT_VALIDITY.getRespDesc());
                }
                break;
            default:
                rglog.warn("不识别的校验参数类型:<{}>", fieldType);
                throw new BizException(OltpRpcdEnum.PARAM_IS_NOT_VALIDITY.getRespCode(), OltpRpcdEnum.PARAM_IS_NOT_VALIDITY.getRespDesc());
        }
    }
}
